/**
   * Copyright (c) 2015-2017, Henry Yang 杨勇 (gismail@foxmail.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.lambkit.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.log.StaticLog;
import com.jfinal.config.*;
import com.jfinal.json.FastJsonFactory;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.render.ErrorRender;
import com.jfinal.template.Engine;
import com.jfinal.template.source.ClassPathSourceFactory;
import com.jfinal.template.source.FileSourceFactory;
import com.lambkit.JFinalApp;
import com.lambkit.LambkitConsts;
import com.lambkit.core.DefaultServerLifecycle;
import com.lambkit.core.Lambkit;
import com.lambkit.core.LambkitServerLifecycle;
import com.lambkit.db.DataSourceManager;
import com.lambkit.db.LambkitDataSource;
import com.lambkit.db.datasource.DataSourceConfig;
import com.lambkit.event.EventKit;
import com.lambkit.module.DefaultModule;
import com.lambkit.module.JFModule;
import com.lambkit.module.JFModules;
import com.lambkit.module.cms.DbSourceFactory;
import com.lambkit.util.Printer;
import com.lambkit.util.StringKit;
import com.lambkit.web.LambkitControllerFactory;
import com.lambkit.web.handler.LambkitHandler;
import com.lambkit.web.template.TemplateFolderPro;
import com.lambkit.web.template.TemplateManager;
import com.lambkit.web.template.TemplatePro;

import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Enumeration;
import java.util.Map;

public abstract class BaseJFinalConfig extends JFinalConfig {
	static final Log log = Log.getLog(BaseJFinalConfig.class);

	private JFModules modules = new JFModules();
	private LambkitServerLifecycle serverLifecycle;

	public abstract void configModule(JFModules modules);

	@Override
	public void configConstant(Constants constants) {
		Printer.print(this, "starter", "---------jfinalconfig configConstant---------");
		String prop = Lambkit.configCenter().getValue("jfinal.prop");
		if(StrUtil.isNotBlank(prop)) {
			Lambkit.configCenter().addConfigCenter(new PropConfigCenter(prop));
		}
		serverLifecycle = Lambkit.get(Lambkit.context().getAttr("serverLifecycleClass", DefaultServerLifecycle.class));
		if(serverLifecycle != null) {
			serverLifecycle.init();
		}
//		if(Lambkit.app() == null) {
//			Class<?> targetClass = this.getClass();
//			App appAnno = targetClass.getAnnotation(App.class);
//			if(appAnno != null) {
//				Lambkit.start(targetClass, new String[]{});
//			} else {
//				Lambkit.start(JFinalApp.class, targetClass, new String[]{});
//			}
//		}
		String defaultModule = Lambkit.configCenter().getValue("jfinal.module.default", "true");
		if("true".equals(defaultModule)) {
			modules.addModule(new DefaultModule());
		}
		configModule(modules);
		modules.configConstant(constants);
		constants.setDevMode(Lambkit.context().getDevMode());
		constants.setMaxPostSize(1024 * 1024 * 2000);
		constants.setReportAfterInvocation(false);
		// 关键配置，请勿改动
		constants.setControllerFactory(new LambkitControllerFactory());
		// 关键配置，请勿改动
		// constants.setJsonFactory(new MixedJsonFactory());
		constants.setJsonFactory(new FastJsonFactory());
		/**
		 * 发送初始化通知
		 */
		//EventKit.sendEvent(JFLambkitConsts.EVENT_INIT, null);
		//TimeUtils.endTime("jfinalconfig configConstant");
	}

	@Override
	public void configRoute(Routes routes) {
		Printer.print(this, "starter", "---------jfinalconfig configRoute---------");
		modules.configRoute(routes);
		//TimeUtils.endTime("jfinalconfig configRoute");
	}

	@Override
	public void configEngine(Engine engine) {
		Printer.print(this, "starter", "---------jfinalconfig configEngine---------");
		TemplateManager.me().setTemplateFolderPro(new TemplateFolderPro());
		TemplateManager.me().setTemplatePro(new TemplatePro());
		String basePath = null;
		String pathType = Lambkit.context().getResourcePathType();
		String prefix = Lambkit.context().getTemplatePath();//"/templates/";
		if(prefix.startsWith("file:")) {
			engine.setSourceFactory(new FileSourceFactory());
			basePath = prefix;
			engine.setBaseTemplatePath(basePath);
			TemplateManager.me().setBaseTemplatePath(basePath);
			TemplateManager.me().setDefaultTemplatePath("/");
			TemplateManager.me().setTemplatePathType(TemplateManager.PATH_TYPE_FILE);
			TemplateManager.me().setPrefix("");
		} else if(prefix.startsWith("{rootPath}")) {
			engine.setSourceFactory(new FileSourceFactory());
			String tempFolder = Lambkit.context().getTemplatePath();
			if(StrKit.isBlank(basePath)) {
				basePath = Lambkit.context().resourceService().getWebResourceFilePath(Lambkit.context().getResourcePath());
			}
			if(basePath.endsWith("/")) {
				basePath = basePath.substring(0, basePath.length() - 1);
			}
			engine.setBaseTemplatePath(basePath);
			//basePath = tempFolder.replace("{rootPath}", basePath);
			TemplateManager.me().setBaseTemplatePath(basePath);
			//TemplateManager.me().setDefaultTemplatePath("/");
			TemplateManager.me().setTemplatePathType(TemplateManager.PATH_TYPE_FILE);
			tempFolder = tempFolder.replace("{rootPath}", "");
			if(!tempFolder.startsWith("/")) {
				tempFolder = "/" + tempFolder;
			}
			tempFolder = StringKit.removeSuffix(tempFolder, "/");
			TemplateManager.me().setDefaultTemplatePath(tempFolder);
			TemplateManager.me().setPrefix(tempFolder);
		} else if(prefix.startsWith("db:")) {
			engine.setSourceFactory(new DbSourceFactory());
			engine.setBaseTemplatePath(null);
			TemplateManager.me().setDefaultTemplatePath("");
			TemplateManager.me().setTemplatePathType(TemplateManager.PATH_TYPE_DATABASE);
			TemplateManager.me().setPrefix("");
		} else if("resources".equalsIgnoreCase(pathType)) {
			engine.setSourceFactory(new ClassPathSourceFactory());
			engine.setBaseTemplatePath(null);
			String tempFolder = Lambkit.context().getTemplatePath();
			tempFolder = StringKit.removePrefix(tempFolder, "/");
			tempFolder = StringKit.removeSuffix(tempFolder, "/");
			TemplateManager.me().setDefaultTemplatePath(URLUtil.CLASSPATH_URL_PREFIX + tempFolder);
			TemplateManager.me().setTemplatePathType(TemplateManager.PATH_TYPE_RESOURCES);
			TemplateManager.me().setPrefix("");
		} else if("classpath".equalsIgnoreCase(pathType)) {
			engine.setSourceFactory(new ClassPathSourceFactory());
			engine.setBaseTemplatePath(null);
			String tempFolder = Lambkit.context().getTemplatePath();
			tempFolder = StringKit.removePrefix(tempFolder, "/");
			tempFolder = StringKit.removeSuffix(tempFolder, "/");
			TemplateManager.me().setDefaultTemplatePath(URLUtil.CLASSPATH_URL_PREFIX + tempFolder);
			TemplateManager.me().setTemplatePathType(TemplateManager.PATH_TYPE_CLASSPATH);
			TemplateManager.me().setPrefix("");
		}else {
			//webapp
			engine.setSourceFactory(new FileSourceFactory());
			if(StrKit.isBlank(basePath)) {
				basePath = PathKit.getWebRootPath();
			}
			if(basePath.endsWith("/")) {
				basePath = basePath.substring(0, basePath.length() - 1);
			}
			engine.setBaseTemplatePath(basePath);
//			String tempFolder = Lambkit.getLambkitConfig().getTemplatePath();
//			if(!tempFolder.startsWith("/")) {
//				tempFolder = "/" + tempFolder;
//			}
//			tempFolder = FileUtils.removeSuffix(tempFolder, "/");
//			basePath = basePath + tempFolder;
			TemplateManager.me().setBaseTemplatePath(basePath);
//			TemplateManager.me().setDefaultTemplatePath("/");
			TemplateManager.me().setTemplatePathType(TemplateManager.PATH_TYPE_WEBAPP);
			String tempFolder = Lambkit.context().getTemplatePath();
			if(!tempFolder.startsWith("/")) {
				tempFolder = "/" + tempFolder;
			}
			tempFolder = StringKit.removeSuffix(tempFolder, "/");
			TemplateManager.me().setDefaultTemplatePath(tempFolder);
			TemplateManager.me().setPrefix(tempFolder);
		}
		if(Lambkit.context().getDevMode()) {
			Printer.print(this,"template", "The JFinal Template resourceType is {}", TemplateManager.me().getTemplatePathType());
			Printer.print(this,"template","The JFinal Template defaultPath is {}", TemplateManager.me().getDefaultTemplatePath());
			Printer.print(this,"template","The JFinal Template basePath is {}", engine.getBaseTemplatePath());
		}

		ErrorRender.setErrorView(400, TemplateManager.me().getPrefix() + "/error/400.html");
		ErrorRender.setErrorView(403, TemplateManager.me().getPrefix() + "/error/403.html");
		ErrorRender.setErrorView(404, TemplateManager.me().getPrefix() + "/error/404.html");
		ErrorRender.setErrorView(414, TemplateManager.me().getPrefix() + "/error/414.html");
		ErrorRender.setErrorView(500, TemplateManager.me().getPrefix() + "/error/500.html");
		ErrorRender.setErrorView(505, TemplateManager.me().getPrefix() + "/error/505.html");

		modules.configEngine(engine);
		//TimeUtils.endTime("jfinalconfig configEngine");
	}

	@Override
	public void configPlugin(Plugins plugins) {
		Printer.print(this, "starter", "---------jfinalconfig configPlugin---------");
		modules.configPlugin(plugins);
		//读取数据库配置
		Map<String, LambkitDataSource> dbs = DataSourceManager.me().initConifg(plugins);
		//加载数据库initSQL配置
		//加载数据库mapping配置
		for (LambkitDataSource dataSource : dbs.values()) {
			if(DataSourceConfig.NAME_DEFAULT.equals(dataSource.getConfigName())) {
				if(modules!=null) {
					for (JFModule module : modules.getModules()) {
						if(module!=null) {
							module.configMapping(dataSource);
						}
					}
				}
			} else {
				if(modules!=null) {
					for (JFModule module : modules.getModules()) {
						if(module!=null) {
							module.configMapping(dataSource.getConfigName(), dataSource);
						}
					}
				}
			}
		}
		//TimeUtils.endTime("jfinalconfig configPlugin");
	}

	@Override
	public void configInterceptor(Interceptors interceptors) {
		Printer.print(this, "starter", "---------jfinalconfig configInterceptor---------");
		modules.configInterceptor(interceptors);
		//TimeUtils.endTime("jfinalconfig configInterceptor");
	}

	@Override
	public void configHandler(Handlers handlers) {
		Printer.print(this, "starter", "---------jfinalconfig configHandler---------");
		handlers.add(new LambkitHandler());
		modules.configHandler(handlers);
		//TimeUtils.endTime("jfinalconfig configHandler");
	}

	@Override
	public void onStart() {
		Printer.print(this, "starter", "---------jfinalconfig onStart---------");
		//LambkitNodeManager.me().initNode();
		super.onStart();
		if(serverLifecycle != null) {
			serverLifecycle.start();
		}
		modules.onStart();
		/**
		 * 发送启动完成通知
		 */
		EventKit.sendEvent(LambkitConsts.EVENT_STARTED, null);
		//TimeUtils.endTime("jfinalconfig onStart");
	}

	@Override
	public void onStop() {
		Printer.print(this, "starter", "---------jfinalconfig onStop---------");
		Enumeration<Driver> drivers = DriverManager.getDrivers();
		if (drivers != null) {
			while (drivers.hasMoreElements()) {
				try {
					Driver driver = drivers.nextElement();
					DriverManager.deregisterDriver(driver);
				} catch (Exception e) {
					log.error(e.toString(), e);
				}
			}
		}
		modules.onStop();
		if(serverLifecycle != null) {
			serverLifecycle.stop();
		}
		//TimeUtils.endTime("jfinalconfig onStop");
	}


}
